﻿#if (WINDOWS_PHONE == true)

using System;
using System.IO;
using System.Net;
using System.Net.Sockets;
using Microsoft.Phone.Reactive;
using Polenter.Serialization;
using SoTools.Communicator.Messages;
using System.Diagnostics;

namespace SoTools.Communicator
{
	public sealed partial class Communicator
	{
        private bool _joined = false;
        private UdpAnySourceMulticastClient _client = null;

		public void Publish(BaseMessage message)
		{
            if (!_joined)
                return;

			using (var ms = new MemoryStream())
			{
				var serializer = new SharpSerializer(true);
				serializer.Serialize(message, ms);

				ms.Flush();
				ms.Position = 0;
				var buffer = new byte[ms.Length];
				ms.Read(buffer, 0, buffer.Length);

                _client.BeginSendToGroup(buffer, 0, buffer.Length, _client.EndSendToGroup, null);
			}
		}

		public IObservable<T> GenerateObservable<T>() where T : BaseMessage
		{
			return Observable.FromEvent<BaseMessageEventArgs>(h => OnMessageReceived += h, h => OnMessageReceived -= h)
				.Where(args => args.EventArgs.Message is T)
				.Select(args => args.EventArgs.Message as T);
		}

		public void Listen()
		{
            if (_networkObserver != null)
				return;

            if (_client != null)
                _client.Dispose();

            _joined = false;

            _client = new UdpAnySourceMulticastClient(_multicastAddress, _multicastPort);

			var buffer = new byte[10240];
            _networkObserverFactory = Observable.FromAsyncPattern((callback, obj) => _client.BeginReceiveFromGroup(buffer, 0, buffer.Length, callback, obj),
																  r =>
																  {
																	  IPEndPoint endpoint;
                                                                      var size = _client.EndReceiveFromGroup(r, out endpoint);
																	  var result = new byte[size];
																	  Array.Copy(buffer, result, size);
																	  return result;
																  });

            _client.BeginJoinGroup(result =>
                                    {
                                        _client.EndJoinGroup(result);

                                            // Multicast successfully joined !
                                            _joined = true;

                                            // We don't want to receive the messages we send.
                                            _client.MulticastLoopback = true;

                                            _networkObserver = _networkObserverFactory.Invoke().Subscribe(OnReceive);
                                    },
                                    null);
		}
	}
}

#endif